package com.drakulo.games.ais.ui.component.window;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

import com.drakulo.games.ais.core.GameData;
import com.drakulo.games.ais.core.Resource;
import com.drakulo.games.ais.core.building.BuildingCategory;
import com.drakulo.games.ais.core.building.BuildingHelper;
import com.drakulo.games.ais.core.building.BuildingLevelData;
import com.drakulo.games.ais.core.building.BuildingType;
import com.drakulo.games.ais.core.delayed.BuildingAction;
import com.drakulo.games.ais.core.delayed.PreparationAction;
import com.drakulo.games.ais.core.io.BuildingIO;
import com.drakulo.games.ais.ui.I18n;
import com.drakulo.games.ais.ui.ImageManager;
import com.drakulo.games.ais.ui.UIHelper;
import com.drakulo.games.ais.ui.component.ActionHandler;
import com.drakulo.games.ais.ui.component.MultilineLabel;
import com.drakulo.games.ais.ui.component.UIComponent;
import com.drakulo.games.ais.ui.component.button.Button;
import com.drakulo.games.ais.ui.component.button.ImageButton;
import com.drakulo.games.ais.ui.state.SectorState;

import de.matthiasmann.twl.Label;

public class BuildWindow extends UIComponent {
	/** Basic padding used in the window */
	private static final int PADDING = 5;

	/** Industrial buildings buttons */
	private List<Button> buttons;
	/** Special handling for the command center button */
	private Button cmButton;
	/** The play state */
	private SectorState parent;
	/** Flag indicating if the command center is built */
	private boolean commandCenterBuilt;
	/** The building description label */
	private MultilineLabel descLabel;
	/** Hover flag to trigger data zone cleaning */
	private boolean hoverFlag;
	/** Resource costs */
	Map<Resource, BigDecimal> costMap;
	Map<Resource, BigDecimal> earnMap;
	/** The resource labels */
	private Map<Resource, Label> costLabels;
	private Map<Resource, Label> earnLabels;
	/** Cost title */
	private Label costLabel;
	/** Income title */
	private Label earnLabel;

	/**
	 * Constructor
	 * 
	 * @param parent
	 *            - the parent GameState
	 * @param width
	 *            - the window width
	 * @param height
	 *            - the window height
	 * @param ox
	 *            - the window w coordinate
	 * @param oy
	 *            - the window y coordinate
	 */
	public BuildWindow(SectorState parent, int width, int height, int ox, int oy) {
		this.setOX(ox);
		this.setOY(oy);
		this.setWidth(width);
		this.setHeight(height);
		this.parent = parent;
		this.buttons = new ArrayList<Button>();

		// Creating buttons
		final int pitch = ImageButton.IB_DEFAULT_SIZE + 2;
		final int initialX = getOX() + 10;
		final int initialY = getOY() + 10;
		int x = initialX;
		int y = initialY;

		// Industrial buildings
		x = initialX;
		List<BuildingType> types = BuildingType
				.values(BuildingCategory.INDUSTRIAL);
		for (BuildingType type : types) {
			Button button = createBuildingButton(type);
			button.setPosition(x, y);
			buttons.add(button);
			x += pitch;
		}

		// Civil buildings
		x = initialX;
		y += ImageButton.IB_DEFAULT_SIZE + 15;
		types = BuildingType.values(BuildingCategory.CIVIL);
		for (BuildingType type : types) {
			Button button = createBuildingButton(type);
			button.setPosition(x, y);
			if (BuildingType.COMMAND_CENTER.equals(type)) {
				cmButton = button;
				cmButton.enable();
				if (GameData.getSelectedColony().isCommandCenterBuilt()) {
					// Only 1 command center
					button.disable();
				}
			} else if (BuildingType.RESEARCH_CENTER.equals(type)
					&& GameData.getSelectedColony().isResearchCenterBuilt()) {
				// Only 1 research center
				button.disable();
			}
			buttons.add(button);
			x += pitch;
		}

		// Terrabot
		ImageButton terrabotButton = new ImageButton("terrabot", x, y);
		terrabotButton.setTitle(I18n.get("terrabot"));
		terrabotButton.disable();
		terrabotButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				PreparationAction pa = BuildingHelper.create(GameData
						.getSelectedColony());
				BuildWindow.this.parent.setSelectedAction(pa);
				hide();
			}
		});
		terrabotButton.setHoverHandler(new ActionHandler() {

			@Override
			public void run() {
				String desc = I18n.get("terrabot.desc");
				Map<Resource, BigDecimal> costMap = new HashMap<Resource, BigDecimal>();
				// TODO Externalize this
				costMap.put(Resource.ENERGY, BigDecimal.valueOf(25));
				displayBuildingData(desc, costMap);
				hoverFlag = true;
			}
		});
		parent.add(terrabotButton);
		buttons.add(terrabotButton);

		y += ImageButton.IB_DEFAULT_SIZE + 25;
		x = getOX() + PADDING * 2;
		descLabel = new MultilineLabel("");
		descLabel.hide();
		descLabel.setPosition(x, y);
		descLabel.setSize(getWidth() - 4 * PADDING, 50);
		parent.add(descLabel);

		costLabels = new HashMap<Resource, Label>();
		earnLabels = new HashMap<Resource, Label>();
		for (Resource r : Resource.values()) {
			Label lc = new Label();
			lc.setTheme("resourceLabel");
			lc.setSize(80, 15);
			parent.add(lc);
			costLabels.put(r, lc);

			Label le = new Label();
			le.setTheme("resourceLabel");
			le.setSize(80, 15);
			parent.add(le);
			earnLabels.put(r, le);
		}

		costLabel = new Label(I18n.get("global.cost"));
		costLabel.setSize(width / 2, 20);
		costLabel.setVisible(false);
		costLabel.setTheme("resourceLabel");
		parent.add(costLabel);

		earnLabel = new Label(I18n.get("global.income"));
		earnLabel.setVisible(false);
		earnLabel.setSize(width / 2, 20);
		earnLabel.setTheme("resourceLabel");
		parent.add(earnLabel);

	}

	/**
	 * Create a generic building button for the given building type
	 * 
	 * @param type
	 *            - the building type
	 * @return the created button
	 */
	private Button createBuildingButton(final BuildingType type) {
		// Load the building cost
		BuildingLevelData data = BuildingIO.getBuildingData(type).getLevelData(
				0);
		final Map<Resource, BigDecimal> costMap = data.getUpgradeCost();

		// Create the button
		ImageButton button = new ImageButton(type.toString());
		button.setTitle(I18n.get(type.getI18n()));
		// Set the build action
		button.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				BuildingAction ba = BuildingHelper.createAction(
						GameData.getSelectedColony(), type, costMap);
				parent.setSelectedAction(ba);
				hide();
			}
		});
		// Set the hover action
		button.setHoverHandler(new ActionHandler() {

			@Override
			public void run() {
				final String desc = I18n.get(type.getDescI18n());
				displayBuildingData(desc, costMap);
				hoverFlag = true;

				BuildingLevelData data = BuildingIO.getBuildingData(type)
						.getLevelData(0);
				BuildWindow.this.costMap = data.getUpgradeCost();
				earnMap = data.getProduction();
			}
		});
		button.disable();
		button.hide();
		parent.add(button);
		return button;
	}

	/**
	 * Displays a building type data in the data zone. Called on hover for all
	 * action buttons
	 * 
	 * @param name
	 *            - the building name
	 * @param desc
	 *            - the building description
	 * @param costMap
	 *            - the build action cost map
	 */
	private void displayBuildingData(String desc,
			Map<Resource, BigDecimal> costMap) {
		descLabel.setText(desc);
		// TODO
	}

	/**
	 * Handle command center construction flag
	 * 
	 * @param built
	 *            - the command center construction flag
	 */
	public void setCommandCenterBuilt(boolean built) {
		if (commandCenterBuilt == built) {
			return;
		}
		commandCenterBuilt = built;
		for (Button b : buttons) {
			if (built) {
				b.enable();
			} else {
				b.disable();
			}
		}

		if (built) {
			cmButton.disable();
		} else {
			cmButton.enable();
		}
	}

	@Override
	public void render(Graphics g) throws SlickException {
		if (!isShown()) {
			return;
		}
		final int btnZoneHeight = ImageButton.IB_DEFAULT_SIZE + 2 * PADDING;
		int x = getOX();
		int y = getOY();

		// The background for buttons
		UIHelper.drawBox(g, x, y, getWidth(), getHeight());

		// First zone : Industrial buildings
		UIHelper.drawDarkBox(g, x += PADDING, y += PADDING, getWidth() - 2
				* PADDING, btnZoneHeight);

		// Second zone : Civil / Robots
		y += btnZoneHeight + PADDING;
		UIHelper.drawDarkBox(g, x, y, getWidth() - 2 * PADDING, btnZoneHeight);

		// The rendering of the buttons is handled by the GameState

		// Render of data zone
		y += btnZoneHeight + PADDING;
		int height = getHeight() - (y - getOY()) - PADDING;
		UIHelper.drawDarkBox(g, x, y, getWidth() - 2 * PADDING, height);

		// The resources cost / earn
		Resource[] resources = Resource.values();
		Image img;
		y += btnZoneHeight + 25;
		final int sx = getOX() + getWidth() / 2 - 100;
		x = sx;

		costLabel.setPosition(getOX() - 25, y - 25);
		earnLabel.setPosition(getOX() + costLabel.getWidth() - 25, y - 25);
		for (Resource r : resources) {
			UIHelper.drawDarkBox(g, x, y += 3, 24, 20);
			img = ImageManager.getGfx(r.getGfxBase() + "-small");
			img.draw(x + 3, y, r.getColor());

			String costValue = "";
			if (costMap != null) {
				costValue = costMap.get(r).toString();
			}
			Label lbl = this.costLabels.get(r);

			final int zoneHeight = 15;
			UIHelper.drawDarkBox(g, x + 24, y, lbl.getWidth() + 4, zoneHeight);
			lbl.setPosition(x + 24, y);
			lbl.setText(costValue);
			lbl.setVisible(true);

			x += lbl.getWidth() + 15;
			String earnValue = "";
			if (costMap != null) {
				earnValue = earnMap.get(r).toString();
			}
			Label costLbl = this.earnLabels.get(r);

			UIHelper.drawDarkBox(g, x + 24, y, costLbl.getWidth() + 4,
					zoneHeight);
			costLbl.setPosition(x + 24, y);
			costLbl.setText(earnValue);
			costLbl.setVisible(true);

			y += 20;
			x = sx;
		}
	}

	@Override
	public void update(Input input) throws SlickException {
		hoverFlag = false;
		for (Button b : buttons) {
			b.update(input);
			if (isShown()) {
				b.show();
			} else {
				b.hide();
			}
		}
		if (!hoverFlag) {
			descLabel.setText("");
			Resource[] resources = Resource.values();
			for (Resource r : resources) {
				costLabels.get(r).setText("");
				earnLabels.get(r).setText("");
			}
			costMap = null;
		}
	}

	@Override
	public void show() {
		super.show();
		if (descLabel != null) {
			descLabel.show();
			costLabel.setVisible(true);
			earnLabel.setVisible(true);
		}
		displayLabels(true);
	}

	@Override
	public void hide() {
		super.hide();
		if (descLabel != null) {
			descLabel.hide();
			costLabel.setVisible(false);
			earnLabel.setVisible(false);
		}
		displayLabels(false);
	}

	/**
	 * Shows or hide cost / earn labels
	 * 
	 * @param show
	 *            - true to show labels, false to hide them
	 */
	private void displayLabels(boolean show) {
		for (Resource r : Resource.values()) {
			costLabels.get(r).setVisible(show);
			earnLabels.get(r).setVisible(show);
		}
	}
}
